﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace WinHBM.Core.Net.Http
{

    public delegate void OnSuccess(HttpWebResponse response,JObject data);
    public delegate void OnError(HttpWebResponse response,Exception exception);
    public delegate void BeforeRequestDispatcher(WebRequest request);
    public class RequestHolder
    {
        public WebRequest orig;
        public HttpWebRequest request;
        public byte[] body;
        public OnSuccess OnSuccess;
        public OnError OnError;
    }
    public class HttpClient
    {
        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(HttpClient));

        public string RequestPrefix { get; set; }
        public event BeforeRequestDispatcher BeforeRequestDispatcher;

        private HttpClient()
        {
            
        }

        private HttpClient(string requestPrefix)
        {
            this.RequestPrefix = requestPrefix;
        }

        private static HttpClient inst = new HttpClient();

        public static HttpClient Instance { get { return inst; } }


        /*public JObject execute(WebRequest request)
        {
            //处理 BeforeRequestDispatcher
            if (this.BeforeRequestDispatcher != null)
            {
                this.BeforeRequestDispatcher(request);
            }
            //创建请求对象
            HttpWebRequest httpRequest = request.createHttpRequest();
            if(request.RequestBody != null)
            {
                Stream stream = httpRequest.GetRequestStream();
                byte[] body = request.GetRequestBody();
                stream.Write(body,0,body.Length);
                stream.Flush();
                stream.Close();
            }

            JObject ret = new JObject();
            ret["response"] = new JObject();
            System.Net.HttpWebResponse response = (HttpWebResponse) httpRequest.GetResponse();
            ret["response"]["status_code"] = (int)response.StatusCode;
            //ret["response"][]
            return ret;
            
        }*/


        public void execute(WebRequest request, OnSuccess OnSuccess,OnError OnError)
        {

            //处理 BeforeRequestDispatcher
            if (this.BeforeRequestDispatcher != null)
            {
                this.BeforeRequestDispatcher(request);
            }


            //创建请求对象
            HttpWebRequest httpRequest = request.createHttpRequest();
            //创建请求上下文
            RequestHolder holder = new RequestHolder();
            holder.orig = request;
            holder.OnSuccess = OnSuccess;
            holder.OnError = OnError;
            holder.body = request.GetRequestBody();
            holder.request = httpRequest;

            Logger.Debug("http request:" + request.Url);
            Logger.Debug("request body:" + request.RequestBody);

            //异步发送请求
            httpRequest.BeginGetRequestStream(new AsyncCallback(AsyncExecuteRequest), holder);
        }

        public WebRequest CreateRequest(string url,RequestMethod method,JObject body)
        {
            WebRequest webReq = new WebRequest(this);
            if(url.StartsWith("http") || url.StartsWith("https"))
            {
                webReq.Url = url;
            }
            else
            {
                webReq.Url = RequestPrefix + url;
            }
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            }
            webReq.RequestMethod = method;
            webReq.RequestBody = body;
            return webReq;
        }


        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

        public WebRequest CreateRequest(string url, RequestMethod method)
        {
            return CreateRequest(url, method, null);
        }

        private void AsyncExecuteRequest(IAsyncResult asyncResult)
        {
            RequestHolder holder = (RequestHolder)asyncResult.AsyncState;
            try
            {
                
                HttpWebRequest request = holder.request;
                byte[] body = holder.body;
                if (body != null)
                {
                    Stream stream = request.EndGetRequestStream(asyncResult);
                    stream.Write(body, 0, body.Length);
                    stream.Flush();
                    stream.Close();
                }
                request.BeginGetResponse(new AsyncCallback(AsyncGetResponse), holder);
            }
            catch (Exception e)
            {

                holder.OnError(null, e);
            }
            

        }


        private void AsyncGetResponse(IAsyncResult asyncResult)
        {
            RequestHolder holder = (RequestHolder)asyncResult.AsyncState;
            HttpWebRequest request = holder.request;


            try
            {
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    if (holder.OnError != null)
                    {
                        Logger.Error("response status code:" + response.StatusCode);
                        holder.OnError(response, null);
                        return;
                    }
                }

                //获得响应数据
                Stream stream = response.GetResponseStream();
                StreamReader responseReader = new StreamReader(stream);
                string responseString = responseReader.ReadToEnd();
                Logger.Debug("http response:" + responseString);
                JObject responseJson = JObject.Parse(responseString);
                if (holder.OnSuccess != null)
                {
                    holder.OnSuccess(response, responseJson);
                }
            }
            catch (Exception e)
            {
                Logger.Error("get response error:" + e);
                if (holder.OnError != null)
                {
                    holder.OnError(null, e);
                }
            }
        }
    }
}
